/*******************************************************************************
 * This file is part of blueprint4j www.blueprint4j.org.
 * 
 *     blueprint4j is free software: you can redistribute it and/or modify
 *     it under the terms of the GNU Lesser General Public License as published by
 *     the Free Software Foundation, either version 3 of the License, or
 *     (at your option) any later version.
 * 
 *     blueprint4j is distributed in the hope that it will be useful,
 *     but WITHOUT ANY WARRANTY; without even the implied warranty of
 *     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *     GNU Lesser General Public License for more details.
 * 
 *     You should have received a copy of the GNU Lesser General Public License
 *     along with blueprint4j. If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************************/
package blueprint4j.report.db;

import java.io.File;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Hashtable;
import java.util.Properties;

import blueprint4j.db.DBConnection;
import blueprint4j.db.DBTools;
import blueprint4j.db.DataException;
import blueprint4j.db.Entity;
import blueprint4j.db.EntityChild;
import blueprint4j.db.Field;
import blueprint4j.db.FieldInteger;
import blueprint4j.db.FieldRename;
import blueprint4j.db.FieldString;
import blueprint4j.db.FieldStringSelect;
import blueprint4j.db.FieldTime;
import blueprint4j.db.FieldUnique;
import blueprint4j.db.TableName;
import blueprint4j.report.Report;
import blueprint4j.utils.BindException;
import blueprint4j.utils.Bindable;
import blueprint4j.utils.Log;
import blueprint4j.utils.VectorBindable;
import blueprint4j.utils.VectorFile;
import blueprint4j.utils.VectorString;


/**
 * This class is an entity that represets a scheduled report that gets emailed
 */

public class ScheduleReport extends Entity {
    
    public static String REPORT_SOURCE[] = new String[]{};
    public static String REPORT_NAME[] = new String[]{};
    public static Properties extra_prop [] = null;
    
    public static String EMAIL_FROM_ADDRESS = "noreply@earth";
    
    private static SimpleDateFormat datetime_format= new SimpleDateFormat("yyyyMMddHHmmss"),
            day_format = new SimpleDateFormat("DDD"),
            week_format = new SimpleDateFormat("ww"),
            month_format = new SimpleDateFormat("MM"),
            year_format = new SimpleDateFormat("yyyy"),
            time_format = new SimpleDateFormat("HHmmss");
    
    private static final SimpleDateFormat dayinyear_format= new SimpleDateFormat("DDD"),
            dayinmonth_format= new SimpleDateFormat("dd"),
            dayinweek_format= new SimpleDateFormat("EEE");
    private static final VectorString WEEKDAYS = new VectorString(new String[]{"Sun","Mon","Tue","Wed","Thu","Fri","Sat"});
    
    static final String TABLE_NAME = "d_sch_reports";
    
    public static ScheduleReport CURRENT_USER = null;
    
    private static VectorString PRIVILEGES = null;
    private static Calendar calendar = Calendar.getInstance();
    
    public TableName table_name = new TableName(TABLE_NAME, this);
    
    public static String DAILY = "Daily",WEEKLY = "Weekly",MONTHLY = "Monthly",YEARLY = "Yearly";
    
    public FieldUnique id = new FieldUnique("id", 0, "The Record Identifier", this);
    public FieldString name = new FieldString("name",0,"Name",30,this);
    public FieldString from_address = new FieldString("from_address",0,"From address",50,this);
    public FieldString subject = new FieldString("subject",0,"Email subject",50,this);
    public FieldString e_message = new FieldString("e_message",0,"Email message",50,this);
    public FieldRename r_e_message = new FieldRename("message",e_message,this);
    public FieldStringSelect frequency = new FieldStringSelect("frequency",0,"Report frequency",10,new String[]{DAILY,WEEKLY,MONTHLY,YEARLY},this);
    public FieldStringSelect parameter_frequency = new FieldStringSelect("parameter_frequency",0,"Report timespand",10,new String[]{DAILY,WEEKLY,MONTHLY,YEARLY},this);
    public FieldInteger parameter_frequency_offset = new FieldInteger("parameter_frequency_offset",0,"Report timespand offset",this);
    public FieldTime r_time = new FieldTime("r_time",Field.FIELD_NOT_NULL,"Time to execute",this);
    public FieldInteger r_date = new FieldInteger("r_date",0,"Day in week/month to execute",this);
    public FieldRename r_r_time = new FieldRename("time",r_time,this);
    
    public EntityChild schedule_report_source = new EntityChild(new ScheduleReportSource().schedule_report_id,EntityChild.CHILD_DELETE,this);
    public EntityChild schedule_report_recipient= new EntityChild(new ScheduleReportRecipient().schedule_report_id,EntityChild.CHILD_DELETE,this);
    
    public FieldString bindable = new FieldString("bindable",0,"Entity table name",50,this);
    public FieldString bindable_id = new FieldString("bindable_id",0,"Entity table name",26,this);
    
    public static void setReports(String source[],String names[],Properties extra[]) {
        REPORT_SOURCE = source;
        REPORT_NAME = names;
        extra_prop = extra;
    }
    
    public static String [] getReportName() {return REPORT_NAME;}
    public static String [] getReportSource() {return REPORT_SOURCE;}
    
    public static void setFromAddress(String from_address) {
        EMAIL_FROM_ADDRESS = from_address;
    }
    
    public ScheduleReport() {
        super();
    }
    
    public ScheduleReport(DBConnection connection)
    throws DataException, SQLException {
        super(connection);
    }
    
    public Entity getNewInstance() {
        return new ScheduleReport();
    }
    
    public static VectorScheduleReport getScheduleReport()
    throws SQLException {
        return new VectorScheduleReport((ScheduleReport) new ScheduleReport(DBTools.getDLC()).find("1=1"));
    }
    
    public boolean shouldExecute()
    throws SQLException {
        if (!(new Integer(time_format.format(new Date())).intValue() > new Integer(time_format.format(r_time.get())).intValue())) {
            return false;
        }
        ScheduleReportLog log = ScheduleReportLog.getLastExecute(getConnection(),this);
        if (log == null) {
            return true;
        }
        if (DAILY.equals(frequency.get())) {
            return !day_format.format(log.last_execution.get()).equals(day_format.format(new Date()));
        }
        if (WEEKLY.equals(frequency.get())) {
            if (r_date.get() == null || r_date.get().intValue() <= (WEEKDAYS.indexOf(dayinweek_format.format(new Date())))) {
                return !week_format.format(log.last_execution.get()).equals(week_format.format(new Date()));
            }
        }
        if (MONTHLY.equals(frequency.get())) {
            if (r_date.get() == null || r_date.get().intValue() <= Integer.parseInt(dayinmonth_format.format(new Date()))) {
                return !month_format.format(log.last_execution.get()).equals(month_format.format(new Date()));
            }
        }
        if (YEARLY.equals(frequency.get())) {
            if (r_date.get() == null || r_date.get().intValue() <= Integer.parseInt(dayinyear_format.format(new Date()))) {
                return !year_format.format(log.last_execution.get()).equals(year_format.format(new Date()));
            }
        }
        return false;
    }
    
    public void save()
    throws BindException {
        if (shouldSave()) {
            from_address.set(EMAIL_FROM_ADDRESS);
            /*
            name.set(report.getDisplay());
            if (file_name.get() == null || file_name.get().length() == 0) {
                file_name.set("report");
            }
            if ((export_type.get() == null || export_type.get().equals("PDF")) && !file_name.get().endsWith(".pdf")) {
                file_name.set(file_name.get() + ".pdf");
            } else if ((export_type.get() != null && export_type.get().equals("HTML")) && !file_name.get().endsWith(".html")) {
                file_name.set(file_name.get() + ".html");
            } else if ((export_type.get() != null && export_type.get().equals("CSV")) && !file_name.get().endsWith(".csv")) {
                file_name.set(file_name.get() + ".csv");
            } else if ((export_type.get() != null && export_type.get().equals("XLS")) && !file_name.get().endsWith(".xls")) {
                file_name.set(file_name.get() + ".xls");
            }*/
            super.save();
        }
    }
    
    /*
    public void delete()
    throws BindException {
        try {
            for (
                    ScheduleReportRecipient srr = (ScheduleReportRecipient) new ScheduleReportRecipient(getConnection()).find("schedule_report_id = " + Entity.asSQL(id.get()));
            srr != null;
            srr = (ScheduleReportRecipient) srr.getNextEntity()
            ) {
                srr.delete();
            }
            super.delete();
        } catch (Exception exception) {
            throw new BindException(exception);
        }
    }*/
    
    private Hashtable getOffsetParameters(ScheduleReportSource source)
    throws DataException {
        try {
            Hashtable extra = new Hashtable();
            if (parameter_frequency_offset.get() == null) {
                parameter_frequency_offset.set(new Integer(0));
            }
            Date from = datetime_format.parse(datetime_format.format(new Date()).substring(0,8)+"000000");
            Date to = datetime_format.parse(datetime_format.format(new Date()).substring(0,8)+"235959");
            if (DAILY.equals(parameter_frequency.get())) {
                calendar.setTime(from);
                calendar.add(Calendar.DATE,parameter_frequency_offset.get().intValue());
                from = calendar.getTime();
                calendar.setTime(to);
                calendar.add(Calendar.DATE,parameter_frequency_offset.get().intValue());
                to = calendar.getTime();
            }
            if (WEEKLY.equals(parameter_frequency.get())) {
                calendar.setTime(from);
                calendar.set(Calendar.DAY_OF_WEEK,1);
                calendar.add(Calendar.WEEK_OF_YEAR,parameter_frequency_offset.get().intValue());
                from = calendar.getTime();
                calendar.setTime(to);
                calendar.set(Calendar.DAY_OF_WEEK,7);
                calendar.add(Calendar.WEEK_OF_YEAR,parameter_frequency_offset.get().intValue());
                to = calendar.getTime();
            }
            if (MONTHLY.equals(parameter_frequency.get())) {
                calendar.setTime(from);
                calendar.set(Calendar.DAY_OF_MONTH,1);
                calendar.add(Calendar.MONTH,parameter_frequency_offset.get().intValue());
                from = calendar.getTime();
                calendar.setTime(to);
                calendar.add(Calendar.MONTH,parameter_frequency_offset.get().intValue());
                calendar.set(Calendar.DAY_OF_MONTH,calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
                to = calendar.getTime();
            }
            if (YEARLY.equals(parameter_frequency.get())) {
                calendar.setTime(from);
                calendar.set(Calendar.DAY_OF_YEAR,1);
                calendar.add(Calendar.YEAR,parameter_frequency_offset.get().intValue());
                from = calendar.getTime();
                calendar.setTime(to);
                calendar.add(Calendar.YEAR,parameter_frequency_offset.get().intValue());
                calendar.set(Calendar.DAY_OF_YEAR,calendar.getActualMaximum(Calendar.DAY_OF_YEAR));
                to = calendar.getTime();
            }
            extra.put("from_date",from);
            extra.put("to_date",to);
            // NOW ADD EXTRA PROPERTIES
            if (extra_prop != null) {
                for (int i = 0;i < extra_prop.length;i++) {
                    if (source.report.get().equals(REPORT_SOURCE[i])) {
                        extra.putAll(extra_prop[i]);
                    }
                }
            }
            return extra;
        } catch (Exception exception) {
            throw new DataException(exception);
        }
    }
    
    public void execute()
    throws BindException,SQLException {
        VectorFile vfile= new VectorFile();
        try {
            String to_address = ScheduleReportRecipient.getToAddress(getConnection(),this);
            if (to_address != null && to_address.length() > 0) {
            	//TODO Must fix reporting. DO NOT DELETE
//                Email email = new Email(
//                        to_address,
//                        from_address.get(),
//                        null,
//                        subject.get(),
//                        e_message.get()
//                        );
                for (
                        ScheduleReportSource rsource = (ScheduleReportSource) schedule_report_source.get();
                rsource != null;
                rsource = (ScheduleReportSource) rsource.getNextEntity()
                ) {
                    
                    VectorBindable bindables = new VectorBindable();
                    if (bindable.get() != null && bindable_id.get() != null &&
                            bindable.get().length() > 0 && bindable_id.get().length() > 0
                            ) {
                        Entity bind = (Entity)
                        Class.forName(bindable.get()).getConstructor(
                                new Class[]{DBConnection.class}
                        ).newInstance(new Object[]{getConnection()});
                        bind.id.setAsString(bindable_id.get());
                        bind.loadFromIdField();
                        bindables = new VectorBindable(new Bindable[]{bind});
                    }
//                    Report p_report = new Report(getConnection(),rsource.report.get(),bindables,getOffsetParameters(rsource));
//                    p_report.build();
//                    File report_file = null;
//                    if (rsource.export_type.get() == null || rsource.export_type.get().equals("PDF")) {
//                        report_file = p_report.toPdfFile(rsource.file_name.get());
//                    } else if (rsource.export_type.get().equals("CSV")) {
//                        report_file = p_report.toCsvFile(rsource.file_name.get());
//                    } else if (rsource.export_type.get().equals("XLS")) {
//                        report_file = p_report.toXlsFile(rsource.file_name.get());
//                    } else {
//                        report_file = p_report.toHtmlFile(rsource.file_name.get());
//                    }
          //          email.addAttachment(report_file,rsource.file_name.get());
          //          vfile.add(report_file);
                    //report_file.delete();
                }
                ScheduleReportLog.newLog(getConnection(),true,null,this);
                Log.trace.out("REPORT SENT","["+id.get()+"]");
        //        email.send();
                vfile.delete();
            } else {
                Log.debug.out("REPORT","REPORT ["+id.get()+"] COULD NOT BE SENT, THERE ARE NO RECIPIENTS CONFIGURED");
            }
        } catch (Exception exception) {
            ScheduleReportLog.newLog(getConnection(),false,exception.getMessage(),this);
            throw new BindException(exception);
        } finally {
            vfile.delete();
        }
    }
}
